<!DOCTYPE html>
<!--
=====================================
作者：老曹 QQ:1484743
版权声明：本程序为个人原创、开源程序，禁止用于任何违法用途，任何违法用途均与作者无关。
仅限学习交流，转载请注明出处。如需商用请联系作者。
=====================================
-->
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>图片批量转存工具（断点续传）</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .container { max-width: 600px; margin: auto; }
        .result { background: #f8f8f8; border: 1px solid #ddd; padding: 10px; margin-top: 20px; height: 300px; overflow: auto; }
        .progress { margin-top: 10px; }
        .speed { color: #007bff; }
        .error { color: red; }
        .success { color: green; }
        .btn { padding: 6px 16px; margin-right: 10px; }
    </style>
</head>
<body>
<div class="container">
    <h2>图片批量转存工具（断点续传）</h2>
    <label>上传TXT文件（每行一个图片URL）：</label><br><br>
    <input type="file" id="txtfile" accept=".txt"><br><br>
    <button class="btn" id="startBtn">开始转存</button>
    <button class="btn" id="resumeBtn" style="display:none;">继续</button>
    <div class="progress" id="progress"></div>
    <div class="speed" id="speed"></div>
    <div class="result" id="result"></div>
</div>
<script>
const BATCH_SIZE = 10;
let urls = [];
let current = 0;
let total = 0;
let taskId = '';
let uploading = false;
let startTime = 0;
let uploadedCount = 0;
let lastTime = 0;
let lastUploaded = 0;
let timer = null;

function genTaskId() {
    return 'task_' + Date.now() + '_' + Math.floor(Math.random()*100000);
}

function saveProgress() {
    localStorage.setItem('img_task_id', taskId);
    localStorage.setItem('img_task_current', current);
    localStorage.setItem('img_task_total', total);
}

function loadProgress() {
    taskId = localStorage.getItem('img_task_id') || '';
    current = parseInt(localStorage.getItem('img_task_current') || '0');
    total = parseInt(localStorage.getItem('img_task_total') || '0');
}

function clearProgress() {
    localStorage.removeItem('img_task_id');
    localStorage.removeItem('img_task_current');
    localStorage.removeItem('img_task_total');
}

function showProgress() {
    document.getElementById('progress').innerText = `已上传 ${current} / ${total}`;
}

function showSpeed() {
    const now = Date.now();
    const elapsed = (now - startTime) / 1000;
    const speed = uploadedCount / (elapsed || 1);
    document.getElementById('speed').innerText = `平均速度：${speed.toFixed(2)} 条/秒`;
}

function appendResult(msgs) {
    const resultDiv = document.getElementById('result');
    msgs.forEach(msg => {
        const p = document.createElement('div');
        if (msg.startsWith('已保存')) p.className = 'success';
        if (msg.startsWith('下载失败') || msg.startsWith('无效URL') || msg.startsWith('批次处理失败')) p.className = 'error';
        p.textContent = msg;
        resultDiv.appendChild(p);
    });
    resultDiv.scrollTop = resultDiv.scrollHeight;
}

async function processBatch(batch) {
    const formData = new FormData();
    formData.append('task_id', taskId);
    formData.append('urls', JSON.stringify(batch));
    const resp = await fetch('index.php', { method: 'POST', body: formData });
    return await resp.json();
}

async function uploadLoop() {
    uploading = true;
    startTime = Date.now();
    uploadedCount = current;
    lastTime = startTime;
    lastUploaded = current;
    document.getElementById('startBtn').disabled = true;
    document.getElementById('resumeBtn').style.display = 'none';
    while (current < total && uploading) {
        const batch = urls.slice(current, current + BATCH_SIZE);
        try {
            const result = await processBatch(batch);
            appendResult(result);
        } catch (e) {
            appendResult([`批次处理失败: ${e}`]);
            uploading = false;
            document.getElementById('resumeBtn').style.display = '';
            break;
        }
        current += batch.length;
        uploadedCount = current;
        saveProgress();
        showProgress();
        showSpeed();
        await new Promise(r => setTimeout(r, 200));
    }
    if (current >= total) {
        appendResult(['全部完成！']);
        clearProgress();
        document.getElementById('startBtn').disabled = false;
    }
}

document.getElementById('startBtn').onclick = async function() {
    const fileInput = document.getElementById('txtfile');
    if (!fileInput.files.length) {
        alert('请先选择TXT文件');
        return;
    }
    const file = fileInput.files[0];
    const text = await file.text();
    urls = text.split(/\r?\n/).filter(line => line.trim() !== '');
    total = urls.length;
    current = 0;
    taskId = genTaskId();
    saveProgress();
    document.getElementById('result').innerHTML = '';
    showProgress();
    showSpeed();
    uploadLoop();
    pollProgress();
};

document.getElementById('resumeBtn').onclick = function() {
    loadProgress();
    if (!taskId || !total) {
        alert('没有可恢复的任务');
        return;
    }
    document.getElementById('result').innerHTML = '';
    showProgress();
    showSpeed();
    uploadLoop();
    pollProgress();
};

function pollProgress() {
    if (!taskId) return;
    fetch('progress.php?task_id=' + encodeURIComponent(taskId))
        .then(resp => resp.json())
        .then(data => {
            if (data && data.status) {
                appendResult([`后端状态：${data.status}`]);
            }
            if (uploading && current < total) {
                setTimeout(pollProgress, 2000);
            }
        });
}

window.onload = function() {
    loadProgress();
    if (taskId && current < total) {
        document.getElementById('resumeBtn').style.display = '';
        showProgress();
        showSpeed();
    }
};
</script>
</body>
</html> 